﻿//------------------------------------------------------------------------------
// <copyright company="Tunynet">
//     Copyright (c) Tunynet Inc.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------
using MySql.Data.MySqlClient;
using PetaPoco;
using ReUse.DBUtility;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Tunynet.CMS;
using Tunynet.Common;
using Tunynet.FileStore;
using Tunynet.Post;
using Tunynet.Utilities;

namespace Spacebuilder.Setup
{
    /// <summary>
    /// 升级程序
    /// </summary>
    public class UpgradeController : Controller
    {
        /// <summary>
        /// 文件存储Provider
        /// </summary>
        private IStoreProvider storeProvider;

        private UserService userService;
        private SectionService sectionService;

        public UpgradeController(IStoreProvider storeProvider, UserService userService, SectionService sectionService)
        {
            this.storeProvider = storeProvider;
            this.userService = userService;
            this.sectionService = sectionService;
        }

        /// <summary>
        /// 准备
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Ready()
        {
            return View();
        }

        /// <summary>
        /// 选择升级的数据
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Upgrade_Start1()
        {
            return View();
        }

        /// <summary>
        /// 选择升级的数据
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Upgrade_Start2(string currentVersion, List<string> upgradeModule)
        {
            UpgradeInfoModel upgradeInfoModel = new UpgradeInfoModel();
            upgradeInfoModel.CurrentVersion = currentVersion;
            upgradeInfoModel.UpgradeModule = upgradeModule;

            return View(upgradeInfoModel);
        }

        /// <summary>
        /// 获取数据库链接提供者
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        private string GetProviderName(DBType dbType)
        {
            var providerName = string.Empty;
            switch (dbType)
            {
                case DBType.MySql:
                    providerName = "MySql.Data.MySqlClient";
                    break;
                //case DBType.SqlCE:
                //    providerName = "System.Data.EntityClient";
                //    break;
                case DBType.SqlServer:
                default:
                    providerName = "System.Data.SqlClient";
                    break;
            }
            return providerName;
        }

        /// <summary>
        /// 创建数据库访问对象
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="dbType"></param>
        /// <param name="messages"></param>
        /// <returns></returns>
        private Database CreateDatabase(string connectionString, DBType dbType, ref ConcurrentDictionary<string, string> messages)
        {
            if (messages == null)
                messages = new ConcurrentDictionary<string, string>();

            //DbProviderFactory factory = DbProviderFactories.GetFactory(GetProviderName(dbType));
            string providerName = GetProviderName(dbType);
            try
            {
                return new Database(connectionString, providerName);
            }
            catch (Exception e)
            {
                messages[e.Message] = e.StackTrace;
                return null;
            }
        }

        /// <summary>
        /// 获取安装日志文件名
        /// </summary>
        /// <returns></returns>
        private string GetLogFileName(string upgradeModule)
        {
            string currentDirectory = WebUtility.GetPhysicalFilePath("~/Uploads");
            return $"{currentDirectory}\\{upgradeModule}-upgrade.txt";
        }

        /// <summary>
        /// 确保文件已被创建
        /// </summary>
        /// <param name="fileName">带路径的文件名</param>
        /// <returns></returns>
        private bool EnsureFileExist(string fileName)
        {
            if (System.IO.File.Exists(fileName))
            {
                return true;
            }
            else
            {
                try
                {
                    FileStream fs = new FileStream(fileName, FileMode.CreateNew);
                    fs.Close();
                    return true;
                }
                catch (Exception e)
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// 将升级信息写入升级日志中
        /// </summary>
        /// <param name="messages"></param>
        /// <returns></returns>
        private bool WriteLogFile(ConcurrentDictionary<string, string> messages, string upgradeModule)
        {
            string fileName = GetLogFileName(upgradeModule);
            if (!EnsureFileExist(fileName))
                return false;

            StreamWriter sw = new StreamWriter(fileName, true, Encoding.UTF8);   //该编码类型不会改变已有文件的编码类型
            foreach (var message in messages)
            {
                sw.WriteLine(DateTime.Now.ToString() + "：" + string.Format("{0}:{1}", message.Key, message.Value));
            }
            sw.Close();
            return true;
        }

        /// <summary>
        /// 选择升级的数据
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public JsonResult Upgrade_Start3(UpgradeInfoModel upgradeInfoModel)
        {
            upgradeInfoModel.UpgradeModule = upgradeInfoModel.UpgradeModule.FirstOrDefault().Split(',').ToList();
            string connectString = string.Empty;
            DBType DBType = DBType.SqlServer;
            ConcurrentDictionary<string, string> messages = new ConcurrentDictionary<string, string>();
            int connectionStringsCount = ConfigurationManager.ConnectionStrings.Count;
            if (connectionStringsCount > 0)
                connectString = ConfigurationManager.ConnectionStrings[connectionStringsCount - 1]?.ToString();

            if (upgradeInfoModel.OldConnectionStrings.IndexOf("MySql.Data.MySqlClient") > 1)
                DBType = DBType.MySql;

            upgradeInfoModel.OldConnectionStrings = upgradeInfoModel.OldConnectionStrings.Substring(upgradeInfoModel.OldConnectionStrings.IndexOf("connectionString=") + 18);
            upgradeInfoModel.OldConnectionStrings = upgradeInfoModel.OldConnectionStrings.Substring(0, upgradeInfoModel.OldConnectionStrings.IndexOf("\""));
            Database dbold = CreateDatabase(upgradeInfoModel.OldConnectionStrings, DBType, ref messages);
            Database db = CreateDatabase(connectString, DBType, ref messages);
            var dataName = string.Empty;
            //尝试打开数据库链接，检查数据库是否能够链接上
            try
            {
                dbold.OpenSharedConnection();
                dataName = dbold.Connection.Database;
                dbold.CloseSharedConnection();
            }
            catch (Exception e)
            {
                bool success = false;
                //如果是SQL Server数据库，则再次尝试打开SQLEXPRESS
                if (!success)
                {
                    return Json(new { state = 0, msg = "数据库连接串出错，无法登录数据库服务器" });
                }
            }
            //获取升级脚本
            List<string> fileList = SetupHelper.GetUpgradeFiles(DBType);
            List<string> errorUpgradeModule = new List<string>();
            Dictionary<string, string> adminInfo = new Dictionary<string, string>();
            adminInfo.Add("tn.jinhudemoNew", dataName);
            adminInfo.Add("@", "@@");
            upgradeInfoModel.UpgradeModule.Add("Export");
            foreach (var item in upgradeInfoModel.UpgradeModule)
            {
                try
                {
                    SetupHelper.ExecuteInFile(db, fileList.Where(n => n.Contains(item))?.FirstOrDefault(), out messages, adminInfo);
                }
                catch (Exception e)
                {
                    messages["执行数据库初始化脚本时出现错误，请查看安装日志！"] = StatusMessageType.Error.ToString();
                }

                //移植附件
                try
                {
                    Upgrade(upgradeInfoModel.OldFilePath, item, upgradeInfoModel.OldConnectionStrings, DBType);
                }
                catch (Exception ex)
                {
                    messages[ex.Message] = StatusMessageType.Error.ToString();
                }

                if (messages.Any())
                {
                    errorUpgradeModule.Add(item);
                    WriteLogFile(messages, item);
                }
            }

            upgradeInfoModel.UpgradeModule.Remove("Export");
            TempData["errorUpgradeModule"] = errorUpgradeModule;
            TempData["upgradeModule"] = upgradeInfoModel.UpgradeModule;
            //return Json(new { success = true, connectString = connectString, DBType = DBType });
            return Json(new { state = 1, msg = "升级完成" });
        }

        /// <summary>
        /// 升级完成
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult Upgrade_End()
        {
            return View();
        }

        /// <summary>
        /// 附件升级
        /// </summary>
        /// <param name="sourcePath">源文件路径</param>
        /// <param name="upgradeModule">升级模块</param>
        /// <returns></returns>
        [HttpGet]
        public bool Upgrade(string sourcePath, string upgradeModule, string connString, DBType dBType)
        {
            bool result = dBType == DBType.SqlServer;

            //单独提炼贴吧logo
            if (upgradeModule == "Bar")
            {
                var sql = "SELECT SectionId,UserId,LogoImage  FROM spb_BarSections";
                var sParam = new SqlParameter[0] { };
                AttachmentService attachmentService = new AttachmentService(TenantTypeIds.Instance().Section());
                var barSectionRepository = new SectionRepository();
                if (result)
                {
                    using (SqlDataReader dr = SqlHelper.ExecuteReader(connString, CommandType.Text, sql, sParam))
                    {
                        while (dr.Read())
                        {
                            var datePath = $"{sourcePath}\\{dr["LogoImage"]}";
                            var file = storeProvider.GetFile(datePath);
                            if (file != null)
                            {
                                Attachment attachment = new Attachment(file.OpenReadStream(), $"image/{Path.GetExtension(file.Name).Substring(1)}", file.Name);
                                attachment.AssociateId = (long)dr["SectionId"];
                                attachment.UserId = (long)dr["UserId"];
                                attachment.TenantTypeId = TenantTypeIds.Instance().Section();
                                attachment.Price = 0;
                                attachment.MediaType = MediaType.Image;
                                attachment.Discription = string.Empty;
                                attachmentService.Create(attachment, file.OpenReadStream());
                                var section = sectionService.Get((long)dr["SectionId"]);
                                if (section != null)
                                {
                                    section.FeaturedImageAttachmentId = attachment.AttachmentId;
                                    barSectionRepository.Update(section);
                                }
                            }
                        }
                    }
                }
                else
                {
                    using (MySqlConnection sqlCon = new MySqlConnection(connString))
                    {
                        MySqlCommand cmd = new MySqlCommand(sql, sqlCon);
                        MySqlDataReader reader = null;
                        try
                        {
                            //打开连接
                            sqlCon.Open();
                            //执行查询，并将结果返回给读取器
                            reader = cmd.ExecuteReader();
                            while (reader.Read())
                            {
                                var datePath = $"{sourcePath}\\{reader[2]}";
                                var file = storeProvider.GetFile(datePath);
                                if (file != null)
                                {
                                    Attachment attachment = new Attachment(file.OpenReadStream(), $"image/{Path.GetExtension(file.Name).Substring(1)}", file.Name);
                                    attachment.AssociateId = (long)reader[0];
                                    attachment.UserId = (long)reader[1];
                                    attachment.TenantTypeId = TenantTypeIds.Instance().Section();
                                    attachment.Price = 0;
                                    attachment.MediaType = MediaType.Image;
                                    attachment.Discription = string.Empty;
                                    attachmentService.Create(attachment, file.OpenReadStream());
                                    var section = sectionService.Get((long)reader[0]);
                                    if (section != null)
                                    {
                                        section.FeaturedImageAttachmentId = attachment.AttachmentId;
                                        barSectionRepository.Update(section);
                                    }
                                }
                            }
                        }
                        catch (Exception ex) { }
                        finally
                        {
                            reader.Close();
                            sqlCon.Close();
                        }
                    }
                };
                ThreadRepository threadRepository = new ThreadRepository();
                var threads = threadRepository.GetAll();
                foreach (var item in threads)
                {
                  
                   
                    if (!string.IsNullOrEmpty(item.GetBody()))
                    {
                        item.Body = item.GetBody()?.Replace("/BarThread/", "/Thread/");
                        var body = item.Body;
                        ParsingImage(ref body);
                        item.Body = body.Replace("{zhangzhihuiParsing}", "<img");
                        threadRepository.Update(item);
                    }

                }
            }
            //基础升级
            if (upgradeModule == "Export")
            {
                var sql = "SELECT LinkId,OwnerId,ImageUrl  FROM spb_Links";

                var sParam = new SqlParameter[0] { };
                AttachmentService attachmentService = new AttachmentService(TenantTypeIds.Instance().Link());
                var linkRepository = new LinkRepository();
                if (result)
                {
                    using (SqlDataReader dr = SqlHelper.ExecuteReader(connString, CommandType.Text, sql, sParam))
                    {
                        while (dr.Read())
                        {
                            var datePath = $"{sourcePath}\\{dr["ImageUrl"]}";
                            var file = storeProvider.GetFile(datePath);
                            if (file != null)
                            {
                                Attachment attachment = new Attachment(file.OpenReadStream(), $"image/{Path.GetExtension(file.Name).Substring(1)}", file.Name);
                                attachment.AssociateId = (long)dr["LinkId"];
                                attachment.UserId = (long)dr["OwnerId"];
                                attachment.TenantTypeId = TenantTypeIds.Instance().Link();
                                attachment.Price = 0;
                                attachment.MediaType = MediaType.Image;
                                attachment.Discription = string.Empty;
                                attachmentService.Create(attachment, file.OpenReadStream());
                                var link = linkRepository.Get((long)dr["LinkId"]);
                                if (link != null)
                                {
                                    link.ImageAttachmentId = attachment.AttachmentId;
                                    linkRepository.Update(link);
                                }
                            }
                        }
                    }
                }
                else
                {
                    using (MySqlConnection sqlCon = new MySqlConnection(connString))
                    {
                        MySqlCommand cmd = new MySqlCommand(sql, sqlCon);
                        MySqlDataReader reader = null;
                        try
                        {
                            //打开连接
                            sqlCon.Open();
                            //执行查询，并将结果返回给读取器
                            reader = cmd.ExecuteReader();
                            while (reader.Read())
                            {
                                var datePath = $"{sourcePath}\\{reader[2]}";
                                var file = storeProvider.GetFile(datePath);
                                if (file != null)
                                {
                                    Attachment attachment = new Attachment(file.OpenReadStream(), $"image/{Path.GetExtension(file.Name).Substring(1)}", file.Name);
                                    attachment.AssociateId = (long)reader[0];
                                    attachment.UserId = (long)reader[1];
                                    attachment.TenantTypeId = TenantTypeIds.Instance().Link();
                                    attachment.Price = 0;
                                    attachment.MediaType = MediaType.Image;
                                    attachment.Discription = string.Empty;
                                    attachmentService.Create(attachment, file.OpenReadStream());
                                    var link = linkRepository.Get((long)reader[0]);
                                    if (link != null)
                                    {
                                        link.ImageAttachmentId = attachment.AttachmentId;
                                        linkRepository.Update(link);
                                    }
                                }
                            }
                        }
                        catch (Exception ex) { }
                        finally
                        {
                            reader.Close();
                            sqlCon.Close();
                        }
                    }
                }
            }

          

            //单独更改CMS内容链接
            if (upgradeModule == "CMS")
            {
                ContentItemRepository contentItemRepository = new ContentItemRepository();
                var contentItems = contentItemRepository.GetAll();
                foreach (var item in contentItems)
                {
                   
                    if (!string.IsNullOrEmpty(item.Body))
                    {
                        item.Body = item.Body?.Replace("/CMS/", "/ContentItem/");

                        var body = item.Body;
                        ParsingImage(ref body);
                        item.Body = body.Replace("{zhangzhihuiParsing}", "<img");
                        contentItemRepository.Update(item);
                    }

                
                   
                }
            }

            //单独更改Blog内容链接
            if (upgradeModule == "Blog")
            {
                ContentItemRepository contentItemRepository = new ContentItemRepository();
                var contentItems = contentItemRepository.GetAll();
                foreach (var item in contentItems)
                {

                    if (!string.IsNullOrEmpty(item.Body))
                    {
                        item.Body = item.Body?.Replace("/Blog/", "/ContentItem/");

                        var body = item.Body;
                        ParsingImage(ref body);
                        item.Body = body.Replace("{zhangzhihuiParsing}", "<img");
                        contentItemRepository.Update(item);
                    }

                  
                }
            }

            //当前移植的路径遍历 标示
            string currentDirectory = string.Empty;
            List<Dictionary<string, string>> folderList = new List<Dictionary<string, string>>();
            var url = sourcePath;
            var fileurl = WebUtility.GetPhysicalFilePath("~/Uploads"); ;
            GetFile(url, string.Empty, folderList, currentDirectory, upgradeModule);
            foreach (var item in folderList)
            {
                var folder = item.FirstOrDefault();
                switch (folder.Key)
                {
                    case "AskAnswer":
                        CreateFile(folder.Value, "AskAnswer", "Answer", fileurl);
                        break;

                    case "AskQuestion":
                        CreateFile(folder.Value, "AskQuestion", "Question", fileurl);
                        break;

                    case "Avatars":
                        CreateFile(folder.Value, "Avatars", "Avatars", fileurl);
                        break;

                    case "BarPost":
                        CreateFile(folder.Value, "BarPost", "Thread", fileurl);
                        break;

                    case "BarThread":
                        CreateFile(folder.Value, "BarThread", "Thread", fileurl);
                        break;

                    case "CMS":
                        CreateFile(folder.Value, "CMS", "ContentItem", fileurl);
                        break;

                    case "Blog":
                        CreateFile(folder.Value, "Blog", "ContentItem", fileurl);
                        break;

                    case "ContentItem":
                        CreateFile(folder.Value, "ContentItem", "ContentItem", fileurl);
                        break;
                }
            }

            return true;
        }

        /// <summary>
        /// 解析图片的浏览样式
        /// </summary>
        /// <param name="body"></param>
        public void ParsingImage(ref string body)
        {
            if (body.Contains("<img"))
            {
                var index = body.IndexOf("<img");
                var ual = body.Substring(index);
                var index2 = ual.IndexOf("/>");
                var re = ual.Substring(0, index2 + 2);

                index = re.IndexOf("src=\"") == -1 ? re.IndexOf("src=\'") : re.IndexOf("src=\"");
                ual = re.Substring(index + 5);
                index2 = ual.IndexOf("\"") == -1 ? ual.IndexOf("\'") : ual.IndexOf("\"");
                var href = ual.Substring(0, index2);
                string mub = $"<a class='fancybox' href='{href}' data-fancybox-group='gallery'>{re.Replace("<img", "{zhangzhihuiParsing}")}</a>";
                body = body.Replace(re, mub);
                ParsingImage(ref body);
            }

        }


        /// <summary>
        /// 重新创建附件
        /// </summary>
        /// <param name="folderUrl">文件夹路径</param>
        /// <param name="sourceName">源文件基础目录</param>
        /// <param name="folderName">路径要替换的名字</param>
        /// <param name="objectUrl"></param>
        public void CreateFile(string folderUrl, string sourceName, string folderName, string objectUrl)
        {
            var files = storeProvider.GetFiles(folderUrl, true);
            string[] datePaths = new string[] { folderName };
            var path = $"{objectUrl}\\{folderUrl.Substring(folderUrl.IndexOf(sourceName))}";
            //datePaths = datePaths.Concat(DateTime.Now.ToString("yyyy-MM-dd").Split('-')).ToArray();
            //var datePath = storeProvider.JoinDirectory(datePaths);
            //var path = $"{objectUrl}\\{datePath}" ;

            foreach (var file in files.Where(n => n.Name.IndexOf("-") < 1))
            {
                var fileName = file.Name;
                if (folderName == "Avatars")
                {
                    var index = file.Name.LastIndexOf('_');
                    if (index < 1)
                    {
                        index = file.Name.LastIndexOf('.');
                    }
                    var userName = file.Name.Substring(0, index);
                    long userId = 0;
                    if (!long.TryParse(userName, out userId))
                    {
                        userName = userName.Substring(userName.IndexOf('_') + 1);
                        if (!long.TryParse(userName, out userId))
                        {
                        }
                    }
                    var datePath = userService.GetAvatarDirectlyUrl(userId);
                    if (!string.IsNullOrEmpty(datePath))
                    {
                        path = Tunynet.Utilities.WebUtility.GetPhysicalFilePath(datePath);

                        fileName = path.Substring(path.LastIndexOf("\\") + 1);
                        path = path.Substring(0, path.LastIndexOf("\\"));
                        storeProvider.AddOrUpdateFile(path, fileName, file.OpenReadStream());
                    }

                    datePath = userService.GetAvatarDirectlyUrl(userId, AvatarSizeType.Big);

                    if (!string.IsNullOrEmpty(datePath))
                    {
                        path = Tunynet.Utilities.WebUtility.GetPhysicalFilePath(datePath);

                        fileName = path.Substring(path.LastIndexOf("\\") + 1);
                        path = path.Substring(0, path.LastIndexOf("\\"));
                        storeProvider.AddOrUpdateFile(path, fileName, file.OpenReadStream());
                    }
                }
                else if (!string.IsNullOrEmpty(path))
                {
                    storeProvider.AddOrUpdateFile(path.Replace(sourceName, folderName), fileName, file.OpenReadStream());
                }
            }
        }

        /// <summary>
        /// 获取所有要升级的附件路径
        /// </summary>
        /// <param name="url">文件根路径</param>
        /// <param name="nextFolderName">下一个根路径下的子路经</param>
        /// <param name="folderList">路径集合包括根路径下的子路经和详细路径</param>
        /// <param name="currentDirectory">当前转换的根路径下的文件夹名称</param>
        ///  <param name="upgradeModule">升级模块</param>
        public void GetFile(string url, string nextFolderName, List<Dictionary<string, string>> folderList, string currentDirectory, string upgradeModule)
        {
            if (!string.IsNullOrEmpty(nextFolderName))
            {
                if (!(url.IndexOf(currentDirectory) > 1))
                {
                    currentDirectory = nextFolderName;
                }

                url = $"{url}\\{nextFolderName}";
            }
            DirectoryInfo theFolder = new DirectoryInfo(url);
            DirectoryInfo[] dirInfo = theFolder.GetDirectories();
            switch (upgradeModule)
            {
                case "Ask":
                    dirInfo = dirInfo.Where(n => n.Name.Contains("Ask")).ToArray();
                    break;

                case "Bar":
                    dirInfo = dirInfo.Where(n => n.Name.Contains("Bar")).ToArray();
                    break;

                case "CMS":
                    dirInfo = dirInfo.Where(n => n.Name.Contains("CMS") || n.Name.Contains("ContentItem")).ToArray();
                    break;

                case "Blog":
                    dirInfo = dirInfo.Where(n => n.Name.Contains("Blog")).ToArray();
                    break;

                case "Export":
                    dirInfo = dirInfo.Where(n => n.Name.Contains("Link") || n.Name.Contains("Avatars")).ToArray();
                    break;
            }
            //遍历文件夹
            foreach (DirectoryInfo NextFolder in dirInfo)
            {
                GetFile(url, NextFolder.Name, folderList, currentDirectory, string.Empty);
            }
            Dictionary<string, string> dic = new Dictionary<string, string>();
            dic.Add(currentDirectory.ToString(), url);
            folderList.Add(dic);
        }
    }
}